﻿using UnityEngine;
using System;

namespace TC
{
    public interface IEntity<T>
    {
        T target { get; }
    }

    public interface IScalable
    {
        float maxScale { get; }
        float minScale { get; }
        float scaleStep { get; }
        float curScale { get; set; }

        void RefreshScale(float newScale, Vector2 mousePosition);
    }

    public interface IEventProcess
    {
        void OnEvent();
    }
    
    public abstract class Surface : IGraphic, IEventProcess, IScalable, ISerialize
    {
        /// <summary>
        /// relativeRect
        /// 对于graph而言，该值为相对ViewRect的Rect
        /// 对于Graph下的元素而言，该值为相对Graph relativeRect的Rect
        /// </summary>
        public Rect relativeRect;
        public Vector2 position;                                        // relativeRect左上角顶点相对父元素的坐标
        public Vector2 size;
        public bool isContaining;                                       // 鼠标位置是否落于relativeRect中
        public bool isHovering = false;


        public float maxScale { get; } = 1.3f;
        public float minScale { get; } = 0.1f;
        public float scaleStep { get; } = 0.1f;
        public float curScale { get; set; } = 1.3f;

        public virtual void OnDraw(Rect rect) { }

        public virtual void OnCreate() { }

        public virtual void OnDestroy() { }

        public virtual void RefreshScale(float newScale, Vector2 mousePosition)
        {
            curScale = newScale;
            RefreshStyle();
            RefreshSize();
        }

        public virtual void RefreshStyle() { }

        public virtual void RefreshSize() { }

        #region 事件检测

        public virtual void OnEvent()
        {
            Event e = Event.current;
            CheckIsContaining();
            ChildrenEventHandler();
            if (e.isKey) { KeyCodeEventHandler(); }
            else switch (e.type)
                {
                    case EventType.MouseDown: { MouseDownEventHandler(); break; }
                    case EventType.MouseDrag: { MouseDragEventHandler(); break; }
                    case EventType.MouseUp: { MouseUpEventHandler(); break; }
                    case EventType.MouseMove: { MouseMoveEventHandler(); break; }
                    case EventType.Used: { UsedEventHandler();break; }
                    case EventType.ScrollWheel: { ScrollWheelEventHandler(); break; }
                    default: break;
                }
        }

        public virtual void CheckIsContaining()
        {
            isContaining = relativeRect.Contains(Event.current.mousePosition);
        }

        public virtual void ChildrenEventHandler() { }

        public virtual void KeyCodeEventHandler() { }

        public virtual void MouseDownEventHandler() { }

        public virtual void MouseDragEventHandler() { }

        public virtual void MouseUpEventHandler() { }

        public virtual void MouseMoveEventHandler()
        {
            Event e = Event.current;
            if (isContaining)
            {
                isHovering = true;
            }
            else { isHovering = false; }
        }

        public virtual void UsedEventHandler()
        {
            isHovering = false;
        }

        public virtual void ScrollWheelEventHandler() { }

        #endregion

        #region 序列化
        public virtual void OnSerialize_t(ISerializeEntity entity)
        {
            Surface_entity s = entity as Surface_entity;
            s.classType = this.GetType().AssemblyQualifiedName;
            s.rect = relativeRect;
            s.position = position;
            s.size = size;
            s.scale = curScale;
        }

        public virtual void OnDeserialize_t(ISerializeEntity entity)
        {
            Surface_entity s = entity as Surface_entity;
            relativeRect = s.rect;
            position = s.position;
            size = s.size;
            curScale = s.scale;
        }

        public virtual ISerializeEntity CreateEntity()
        {
            return new Surface_entity();
        }

        #endregion
    }
    
    public abstract class EntitySurface<T> : Surface
    {
        public T target { get; private set; }
        public EntitySurface(T target) { this.target = target; }
    }

}
